	//
//  DDVerifyThread.m
//  PrivateCloud
//
//  Created by mars on 13-10-16.
//  Copyright (c) 2013年 sarah doo. All rights reserved.
//

#import "DDVerifyThread.h"
#import "GCDAsyncSocket.h"
#import "DDExchangeTokenMask.h"
#import "DDHdrCloud.h"
#import "DDExchangeTokenMaskACK.h"
#import "NSString+md5.h"
#import "DDLogin.h"
#import "DDLoginACK.h"
#import "DDClientInfo.h"
#import "DDExchangeInformation.h"
#import "DDTCPListenThread.h"
#import "DDConstants.h"
#import "DDFileInfo.h"
#import "DDFolderInfo.h"
#import "DDReportFile.h"
#import "DDDownloadFile.h"
#import "IOOperation.h"
#import "DDDownloadFileACK.h"
#import "FileOperation.h"
#import "DDAddressBookUtils.h"
#import "DDDownLoadAddress.h"
#import "TestAddressBook.h"
#import "DDCommentDic.h"
#import "AppUtil.h"
#import "DDLogout.h"
#import  <ImageIO/ImageIO.h>
#include <AssetsLibrary/AssetsLibrary.h>
#define RECV_HEAD_TAG 1
#define RECV_BODY_TAG 2

static DDVerifyThread *_verifyThread;

@implementation DDVerifyThread


@synthesize sendSocket = _sendSocket;
@synthesize host,port,myTokenMaskStr,pwd,currentDownloadList,currentUploadList,totalLength,currentPer,alreadyDownloadLength,dealFileCallback,uploadVcfFlag,uploadBookCallback;


+ (DDVerifyThread*)sharedVerifyThread{
    if(_verifyThread == nil){
        _verifyThread = [[DDVerifyThread alloc] init];
    }
    return _verifyThread;
}

- (id)init
{
    if(_verifyThread == nil){
        NSLog(@"init send");
        //生成一个队列，发送的消息都需要放置在这个队列当中
        dispatch_queue_t queue = dispatch_get_main_queue();
        //生成用户发送消息的对象
        _sendSocket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:queue];
    }
    _verifyThread = self;
    return self;
}

- (id)initWithHost:(NSString*)vhost port:(int)vport pwd:(NSString*)vpwd{
    if(_verifyThread == nil){
        _verifyThread = [self init];
    }
    [_verifyThread setHost:vhost];
    [_verifyThread setPort:vport];
    _verifyThread.port = TCP_LISTEN_PORT;
    return _verifyThread;
}

- (void)sendMessage:(DDHdrCloud *)msg{
    [[[DDVerifyThread sharedVerifyThread]sendSocket]writeData:[msg entity] withTimeout:-1 tag:[msg cmd]];
//    [_sendSocket writeData:[msg entity] withTimeout:-1 tag:[msg cmd]];
}

//调用该函数开始访问服务器
- (void) connectToCloud:(DDCloudInfo*)cloudInfo andPassword:(NSString*) password{
    //开始连接对方之前，首先启动自己的监听线程
//    DDTCPListenThread* tcpListenThread = [[DDTCPListenThread alloc]init];
    DDTCPListenThread* tcpListenThread = [DDTCPListenThread sharedTCPListener];
    NSString* hostStr = cloudInfo.adderss;
    //FIX ME 按照道理来说，这里是不应该进行扫描的,应该把连接和扫描放在同一个线程当中
    FileOperation* fileOp = [[FileOperation alloc]init];
//    NSArray* allLocalFolderInfos = [fileOp searchAllFiles];
//    [DDConstants removeAllFilesByCode:LOCAL_CODE];
//    [DDConstants removeLocalFolders];
//    [[DDConstants shardLocalFolderInfos]addObjectsFromArray:allLocalFolderInfos];
//    [DDConstants addFiles:allLocalFolderInfos andCode:LOCAL_CODE];
    self.pwd = password;
    BOOL flag = NO;
    NSError* error = Nil;
    flag = [_sendSocket connectToHost:hostStr onPort:TCP_LISTEN_PORT withTimeout:5 error:&error];
    if (!flag) {
        NSLog(@"Failed to create socket");
    }
//    if(![_sendSocket connectToHost:hostStr onPort:TCP_LISTEN_PORT withTimeout:5 error:nil]){
//        NSLog(@"连接失败");
    
//    }
//    if (![_sendSocket connectToHost:hostStr onPort:TCP_LISTEN_PORT error:nil]) {
//        
//    }
    
}

-(void)reportFileList:(NSArray *)folderList{
    //FIX ME这里使用测试数据，使用服务器端的文件列表；
//    DDConstants *constants = [DDConstants sharedConstants];
//    NSArray* serverFolderInfos = [DDConstants shardServerFolderInfos];
    NSMutableArray* allFileList = [[NSMutableArray alloc]init];
    for (DDFolderInfo* info in folderList) {
        [allFileList addObjectsFromArray:[info files]];
    }
    
    if([allFileList count]==0){
        //FIX ME
        NSLog(@"SEND---发送文件列表为空");
        DDReportFile* firstReport = [[DDReportFile alloc]initWithData:0 fileCount:0 fileInfos:nil];
//        [_sendSocket writeData:[firstReport entity] withTimeout:-1 tag:CloudCmd_ReportFile];
        [self sendMessage:firstReport];
        
        DDReportFile* endReport = [[DDReportFile alloc]initWithData:2 fileCount:0 fileInfos:nil];
//        [_sendSocket writeData:[endReport entity] withTimeout:-1 tag:CloudCmd_ReportFile];
        [self sendMessage:endReport];
    }
    
    int pageCount = ([allFileList count] + 5 - 1) /5;
    for(int i =0 ;i < pageCount;i++){
        int type = 0;
        if(i == 0){
            type = 0;
        }
        else if(i <= pageCount - 1){
            type = 1;
        }
        int end = i * 5 + 5;
        if (end > [allFileList count]) {
            end = [allFileList count];
        }
        NSRange range;
        range.location = i * 5;
        range.length = 5;
        if((range.length + range.location)> [allFileList count]){
            range.length = [allFileList count] - range.location;
        }
        NSArray* subFileList = [allFileList subarrayWithRange:range];
        DDReportFile* reportFile = [[DDReportFile alloc]initWithData:type fileCount:[subFileList count] fileInfos:subFileList];
//        [_sendSocket writeData:[reportFile entity] withTimeout:-1 tag:CloudCmd_ReportFile];
        [self sendMessage:reportFile];
    }
    NSArray* endFileList = [[NSArray alloc]init];
    DDReportFile* endReportFile = [[DDReportFile alloc]initWithData:2 fileCount:0 fileInfos:endFileList];
//    [_sendSocket writeData:[endReportFile entity] withTimeout:-1 tag:CloudCmd_ReportFile];
    [self sendMessage:endReportFile];
}

-(void)downFileList:(NSArray *)fileList{
    long totalLength = 0;
    for (DDFileInfo* fileInfo in fileList) {
        long fileLen = [fileInfo fileLength];
        totalLength += fileLen;
    }
    
    DDTCPListenThread* recvThread = [DDTCPListenThread sharedTCPListener];
    recvThread.currentDownloadFileList = fileList;
    recvThread.totalLength = totalLength;
    
    for (DDFileInfo* fileInfo in fileList) {
        
        DDDownloadFile* downFile = [[DDDownloadFile alloc]initWithUid:[fileInfo fileId] andOffset:0 andLength:0xFFFFFFFF];
        [downFile getOffset];
        [_sendSocket writeData:[downFile entity] withTimeout:-1 tag:CloudCmd_DownloadFile];
    }
}

//以下的代码用来实现Socket Delegete当中的函数

#pragma mark Socket Delegate
//该函数为连接成功的回调函数
- (void)socket:(GCDAsyncSocket* )sock didConnectToHost:(NSString *)host port:(uint16_t)port{
    
    //构造并发送连接消息
    DDExchangeTokenMask* myTokenMask = [[DDExchangeTokenMask alloc]initWithTokenMask:@"test"];
    myTokenMaskStr = [myTokenMask getTokenMask];
    //发送交换token mask的指令
    //NSString
    [sock writeData:[myTokenMask entity] withTimeout:-1 tag:CloudCmd_ExchangeTokenMask];
    int tokenMaskAckLength = HEADER_LENGTH + TOKEN_MASK_LENGTH * 2;
    //开始接受
    [sock readDataToLength:20 withTimeout:-1 tag:RECV_HEAD_TAG];
}
//该函数为发送数据成功的回调函数
- (void)socket:(GCDAsyncSocket* )sock didWriteDataWithTag:(long)tag{
    
}

//该函数为收到数据的回调函数
- (void)socket:(GCDAsyncSocket* )sock didReadData:(NSData *)data withTag:(long)tag{
    if(tag == RECV_HEAD_TAG){
        curHdr = [[DDHdrCloud alloc]initWithData:data];
        [curHdr printHead];
        int length = [curHdr length];
        int leftLength = length - HEADER_LENGTH;
        [sock readDataToLength:leftLength withTimeout:-1 tag:RECV_BODY_TAG];
    }
    else if(tag == RECV_BODY_TAG){
        NSMutableData* entity = [[NSMutableData alloc]init];
        [entity appendData:[curHdr entity]];
        [entity appendData:data];
        int curCmd = [curHdr cmd];
        switch (curCmd) {
            case CloudCmd_ExchangeTokenMaskAck:
                NSLog(@"CLOUD---处理指令:CloudCmd_ExchangeTokenMaskAck");
                DDExchangeTokenMaskACK *tokenAck = [[DDExchangeTokenMaskACK alloc]initWithData:entity];
                NSString* peerTokenMask = [tokenAck getTokenMask];
                //NSString* peerTokenMask = @"FKKUMWOSZGFYWVHMLEEJDONIQKRCLPCXMJDRKCMBRPLJFGLLHTWDPZAVFAQLMKI";
                NSMutableString* tokenStr = [[NSMutableString alloc]init];
                [tokenStr appendString:@"CZLMUGRQRYVNWIVBHPHYLAKEEGPLRFSUMNIEWQVJPSSHZETWOSKRFWXOMJNAIWI"];
                peerTokenMask = [peerTokenMask substringToIndex:[peerTokenMask length]-1];
                [tokenStr appendString:peerTokenMask];
                [tokenStr appendString:self.pwd];
                
                NSRange range;
                range.location = 8;
                range.length = 16;
                NSString* actualTokenStr = [[tokenStr md5HexDigest]substringWithRange:range];
                NSData * tokenData = [tokenStr md5Bytes];
                
                DDLogin* login = [[DDLogin alloc]initWithTokenData:tokenData];
                
                [sock writeData:[login entity] withTimeout:-1 tag:CloudCmd_Login];
                
                [sock readDataToLength:HEADER_LENGTH withTimeout:-1 tag:RECV_HEAD_TAG];
                
                break;
            case CloudCmd_LoginAck:
                NSLog(@"CLOUD---处理指令:CloudCmd_LoginAck");
                DDLoginACK* loginAck = [[DDLoginACK alloc]initWithData:entity];
                int result = [loginAck getResult];
                if(result == 0){
                    NSLog(@"client 主动登陆成功");
                    
                    DDClientInfo* clientInfo = [[DDClientInfo alloc]init];
                    NSString *cloudId = [clientInfo getCloudId];
                    NSString *cloudName = [clientInfo getcloudName];
                    NSString *deviceType = [clientInfo cloudType];
                    DDExchangeInformation *exchangeInfo = [[DDExchangeInformation alloc]initWithCloudId:cloudId andName:cloudName andType:deviceType];
                    
                    NSRange testRange;
                    testRange.location = HEADER_LENGTH + CLOUD_ID_LENGTH * 2;
                    testRange.length = CLOUD_NAME_LENGTH;
                    NSData* testData = [[exchangeInfo entity]subdataWithRange:testRange];
                    NSLog(@"%@",testData);
                    [sock writeData:[exchangeInfo entity] withTimeout:-1 tag:CloudCmd_ExchangeInformation];
                    [sock readDataToLength:HEADER_LENGTH withTimeout:-1 tag:RECV_HEAD_TAG];
                    
                }
                else{
                    NSLog(@"client 主动登陆失败");
                    [_connectDelegate onConnectCompleteOn:nil andCode:LOGIN_ERROR_PWD];
                }
                break;
        }
    }
}


//开始上传文件操作，服务器收到上传文件消息之后，会主动连接我方进行数据的下载操作
-(void)uploadFileList:(NSArray*)fileList{
    for (DDFileInfo* info in fileList) {
        long len = [info fileLength];
        totalLength += len;
    }
    [DDVerifyThread sharedVerifyThread].totalLength = totalLength;
    //判断文件是否是图片，如果是图片，就需要首先进行拷贝，然后再发送上传信息
    if ([[DDConstants getFileInfoType:[[fileList objectAtIndex:0]fileName]]isEqualToString:CLOUD_PHOTO]) {
        ALAssetsLibrary* library = [[ALAssetsLibrary alloc]init];
        for (int i = 0; i < [fileList count]; i++) {
            DDFileInfo* fileInfo = [fileList objectAtIndex:i];
            [library assetForURL:[fileInfo url] resultBlock:^(ALAsset *asset) {
                //首先完成拷贝操作，然后再完成发送消息的操作
                NSString * type = [DDConstants getFileInfoType:[fileInfo fileName]];
                NSString* filePath = [NSString stringWithFormat:@"%@%@/%@",[AppUtil getDocPath],type,[fileInfo fileName]];
                [FileOperation writeImage:asset toFileAtPath:filePath];
                DDUploadFile* uploadFile = [[DDUploadFile alloc]initWithFileInfo:fileInfo];
                [[DDVerifyThread sharedVerifyThread]sendMessage:uploadFile];
            } failureBlock:^(NSError *error) {
                
            }];
        }
        
        
        
        
    }
    else{
        [DDVerifyThread sharedVerifyThread].totalLength = totalLength;
        for (DDFileInfo* info in fileList) {
            int uId = [info fileId];
            DDFileInfo* uploadInfo = [DDConstants getLocalFileInfoById:uId];
            DDUploadFile* uploadFile = [[DDUploadFile alloc]initWithFileInfo:uploadInfo];
            [self sendMessage:uploadFile];
        }
    }
    
    
    
}

-(UIImage *)fullSizeImageForAssetRepresentation:(ALAssetRepresentation *)assetRepresentation
{
    UIImage *result = nil;
    NSData *data = nil;
    
    uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t)*[assetRepresentation size]);
    if (buffer != NULL) {
        NSError *error = nil;
        NSUInteger bytesRead = [assetRepresentation getBytes:buffer fromOffset:0 length:[assetRepresentation size] error:&error];
        data = [NSData dataWithBytes:buffer length:bytesRead];
        
        free(buffer);
    }
    
    if ([data length])
    {
        CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
        
        NSMutableDictionary *options = [NSMutableDictionary dictionary];
        
        [options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceShouldAllowFloat];
        [options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceCreateThumbnailFromImageAlways];
        [options setObject:(id)[NSNumber numberWithFloat:640.0f] forKey:(id)kCGImageSourceThumbnailMaxPixelSize];
        //[options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceCreateThumbnailWithTransform];
        
        CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
        
        if (imageRef) {
            result = [UIImage imageWithCGImage:imageRef scale:[assetRepresentation scale] orientation:(UIImageOrientation)[assetRepresentation orientation]];
            CGImageRelease(imageRef);
        }
        
        if (sourceRef)
            CFRelease(sourceRef);
    }
    
    return result;
}


-(void)uploadFile:(DDDownloadFile *)downloadFile{
    int BYTES_PER_SEND = 7 * 1024;
    int fileId = [downloadFile getUid];
    //MARR Q 目前下载文件都是从头下载到尾巴，所以说不需要得到长度和偏移量，只需要查找到这个ID所代表的文件即可
    DDFileInfo* fileInfo = [DDConstants getLocalFileInfoById:fileId];
    //判断需要上传的文件是否是图片，如果是图片，需要首先进行copy，然后再发送上传信息
//    if ([[DDConstants getFileInfoType:[fileInfo fileName]]isEqualToString:CLOUD_PHOTO]) {
//        ALAssetsLibrary* library = [[ALAssetsLibrary alloc] init];
//        [library assetForURL:[fileInfo url] resultBlock:^(ALAsset *asset) {
//            //首先完成拷贝操作，然后再完成发送消息的操作
//            NSString * type = [DDConstants getFileInfoType:[fileInfo fileName]];
//            NSString* filePath = [NSString stringWithFormat:@"%@%@/%@",[AppUtil getDocPath],type,[fileInfo fileName]];
//            [FileOperation writeImage:asset toFileAtPath:filePath];
//            DDUploadFile* uploadFile = [[DDUploadFile alloc]initWithFileInfo:fileInfo];
//            [[DDVerifyThread sharedVerifyThread]sendMessage:uploadFile];
//        } failureBlock:^(NSError *error) {
//            
//        }];
//    }
    long length = [fileInfo fileLength];
    int count = (int)((length + BYTES_PER_SEND - 1)/BYTES_PER_SEND);
    IOOperation * ioOp = [[IOOperation alloc]init];
    long left = length;
    long offset = 0;
    while (left > 0 ) {
        int readLength = BYTES_PER_SEND;
        if(left < BYTES_PER_SEND){
            readLength = (int)left;
        }
        NSData* partData = [ioOp readDataByOffset:offset andLength:readLength andUID:fileId];
        DDDownloadFileACK* downfileAck = [[DDDownloadFileACK alloc]initWithUid:fileId andType:0 andOffset:offset andLength:readLength andData:partData];
        left = left -readLength;
        offset += readLength;
        
        [_sendSocket writeData:[downfileAck entity] withTimeout:-1 tag:CloudCmd_DownloadFileAck];
        
        alreadyDownloadLength += readLength;
        int thisPercent = (int) ((((float) alreadyDownloadLength) / totalLength) * 100);
        if(thisPercent > currentPer){
            currentPer = thisPercent;
            if(dealFileCallback != nil){
                //当代理对象不为空时，调用该方法
                [self.dealFileCallback onProgressChanged:currentPer];
            }
            if (currentPer == 100) {
                if (dealFileCallback != nil) {
                    [self.dealFileCallback onDealFileComplete:nil andCode:DOWNLOAD_SUCCESS];
                    
                }
                alreadyDownloadLength = 0;
                totalLength = 0;
                currentPer = 0;
            }
        }
        [downfileAck release];
    }
    [ioOp release];
    
    
    //上传完成之后，发送最后一个数据包,数据包的type=1
    NSData* emptyData = [[NSData alloc]init];
    DDDownloadFileACK* endFileAck = [[DDDownloadFileACK alloc]initWithUid:fileId andType:1 andOffset:0 andLength:0 andData:emptyData];
    [_sendSocket writeData:[endFileAck entity] withTimeout:-1 tag:CloudCmd_DownloadFileAck];
    [endFileAck release];
}

-(void)uploadAddressBook:(DDDownLoadAddress*)downloadAddress{
    DDAddressBookUtils* bookUtils = [[DDAddressBookUtils alloc]init];
//    [bookUtils createVcard];
    NSString* vcardPath = nil;
    if (uploadVcfFlag) {
        vcardPath = [bookUtils getLocalTempVcfPath];
    }
    else{
        TestAddressBook* test = [[TestAddressBook alloc]init];
        NSMutableArray* allContactInfo = [test getAllContactInfo];
        [test createVcfWithContactInfos:allContactInfo atPath:@"local.vcf"];
        vcardPath = [bookUtils getLocalVcfPath];
    }

    IOOperation* ioOp = [[IOOperation alloc]init];
    
    
    int BYTES_PER_SEND = 1024;
    long length = [ioOp getVcardFileLength:vcardPath];
    int count = (int)((length + BYTES_PER_SEND - 1)/BYTES_PER_SEND);
    long left = length;
    long offset = 0;
    while (left > 0 ) {
        int readLength = BYTES_PER_SEND;
        if(left < BYTES_PER_SEND){
            readLength = (int)left;
        }
        NSData* partData = [ioOp readDataByOffset:offset andLength:readLength andPath:vcardPath];
        DDDownLoadAddressACK* addressAck = [[DDDownLoadAddressACK alloc]initWithType:0 andOffset:offset andFilelength:readLength andData:partData];
        left = left -readLength;
        offset += readLength;
        
        
        [_sendSocket writeData:[addressAck entity] withTimeout:-1 tag:CloudCmd_DownloadAddressBookAck];
    }
    //上传完成之后，发送最后一个数据包,数据包的type=1
    NSData* emptyData = [[NSData alloc]init];
    DDDownLoadAddressACK* endAddressAck = [[DDDownLoadAddressACK alloc]initWithType:1 andOffset:0 andFilelength:0 andData:emptyData];
    [_sendSocket writeData:[endAddressAck entity] withTimeout:-1 tag:CloudCmd_DownloadFileAck];
    if (uploadBookCallback != nil) {
        [uploadBookCallback uploadBookComplete];
    }
    [self setUploadBookCallback:nil];
    if (self.uploadVcfFlag) {
        self.uploadVcfFlag = NO;
    }
}

-(void)downAddressBook{
    DDDownLoadAddress* downloadAddress = [[DDDownLoadAddress alloc]initWithOffset:0 andLength:0xFFFFFFFF];
    [downloadAddress getOffset];
    //[_sendSocket writeData:[downloadAddress entity] withTimeout:-1 tag:CloudCmd_DownloadAddressBook];
    [self sendMessage:downloadAddress];
}

//该函数为连接断开的回调
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
    NSLog(@"disconnection---------------");
}

+(void)closeAndClead{
    //在完成读取和写入操作之后，断开连接
    DDLogout* logout = [[DDLogout alloc]init];
    [[DDVerifyThread sharedVerifyThread]sendMessage:logout];
    [[[DDVerifyThread sharedVerifyThread]sendSocket]disconnectAfterWriting];
    [_verifyThread setSendSocket:nil];
    _verifyThread = nil;
}


@end